package com.xuecheng.media.service.impl;

import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.vod.model.v20170321.GetPlayInfoResponse;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xuecheng.api.media.model.dto.MediaDTO;
import com.xuecheng.api.media.model.qo.QueryMediaModel;
import com.xuecheng.common.domain.code.CommonErrorCode;
import com.xuecheng.common.domain.page.PageRequestParams;
import com.xuecheng.common.domain.page.PageVO;
import com.xuecheng.common.domain.response.RestResponse;
import com.xuecheng.common.enums.common.CommonEnum;
import com.xuecheng.common.enums.content.CourseAuditEnum;
import com.xuecheng.common.exception.ExceptionCast;
import com.xuecheng.common.util.StringUtil;
import com.xuecheng.media.common.constant.MediaErrorCode;
import com.xuecheng.media.common.utils.AliyunVODUtil;
import com.xuecheng.media.convert.MediaConvert;
import com.xuecheng.media.entity.Media;
import com.xuecheng.media.mapper.MediaMapper;
import com.xuecheng.media.service.MediaService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.util.Collections;
import java.util.List;

/**
 * <p>
 * 媒资信息 服务实现类
 * </p>
 *
 * @author itcast
 */
@Slf4j
@Service
public class MediaServiceImpl extends ServiceImpl<MediaMapper, Media> implements MediaService {
    @Autowired
    private RedisTemplate redisTemplate;
    @Value("${aliyun.region}")
    private String region;
    @Value("${aliyun.accessKeyId}")
    private String accessKeyId;
    @Value("${aliyun.accessKeySecret}")
    private String accessKeySecret;
    /*todo
     * 业务分析：
     *   1.判断关键数据
     *       companyId、filename、fileId
     *   2.判断业务数据
     *       媒资信息
     *           判断媒资信息是否存在：fileid
     *   3.将dto转为po数据
     *   4.获得url地址并保存到media表中（不实现）
     *   5.保存媒资信息并返回dto数据
     * */

    @Transactional
    public MediaDTO createMedia(MediaDTO dto) {

//todo 1.判断关键数据
//companyId、filename、fileId
        if (ObjectUtils.isEmpty(dto.getCompanyId()) ||
                StringUtil.isBlank(dto.getFilename()) ||
                StringUtil.isBlank(dto.getFileId())) {
            ExceptionCast.cast(CommonErrorCode.E_100101);
        }
//todo 2.判断业务数据
//媒资信息
//判断媒资信息是否存在：fileid
        LambdaQueryWrapper<Media> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Media::getFileId,dto.getFileId());
        int count = this.count(queryWrapper);
        if(count>0){
            ExceptionCast.cast(MediaErrorCode.E_140008);
        }
//todo 3.将dto转为po数据
        Media media = MediaConvert.INSTANCE.dto2entity(dto);

//todo 4保存媒资信息并返回dto数据
        boolean result = this.save(media);
        if(!result){
            ExceptionCast.cast(MediaErrorCode.E_140001);
        }
        //todo 4.1 重新根据id查询存储的数据    防止字段不同,带来转换异常,所以重新查
        Media byId = this.getById(media.getId());
        MediaDTO mediaDTO = MediaConvert.INSTANCE.entity2dto(byId);
        return mediaDTO;
    }

    @Override
    public PageVO queryMediaList(PageRequestParams params, QueryMediaModel model, Long companyId) {
        //todo 2判断条件:
        //todo 2.1 分页条件:
        Long pageNo = params.getPageNo();
        Integer pageSize = params.getPageSize();

        if (ObjectUtils.isEmpty(pageNo) || pageNo < 0) {
            //判断页数是否为空,为空就把默认值赋值进去
            params.setPageNo(PageRequestParams.DEFAULT_PAGE_NUM);
        }
        if (ObjectUtils.isEmpty(pageSize) || pageSize < 0) {
            //判断每页条数是否为空,为空就把默认值赋值进去
            params.setPageSize(PageRequestParams.DEFAULT_PAGE_SIZE);
        }
        //todo 2.2 构建查询条件 (分页查询的条件)
        LambdaQueryWrapper<Media> queryWrapper = new LambdaQueryWrapper<>();
        //判断是否有条件,如果为空就不加入
        if (StringUtil.isNotBlank(model.getFilename())) {
            queryWrapper.like(Media::getFilename,model.getFilename());
        }
        if (StringUtil.isNotBlank(model.getType())) {
            queryWrapper.eq(Media::getType,model.getType());
        }
        if (StringUtil.isNotBlank(model.getAuditStatus())) {
            queryWrapper.eq(Media::getAuditStatus,model.getAuditStatus());
        }
        queryWrapper.eq(Media::getStatus, CommonEnum.USING_FLAG.getCodeInt());
        if(!(ObjectUtils.isEmpty(companyId))){
            queryWrapper.eq(Media::getCompanyId, companyId);//根据机构id获取相应的机构数据,实现数据分隔
        }else {
            ExceptionCast.cast(CommonErrorCode.E_110009);
        }
        //todo 3 构建mp分页对象 page是分页对象
        Page<Media> page = new Page<>(params.getPageNo(), params.getPageSize());
/*  todo 5 查询数据
                    this 指当前service继承ServiceImpl, ServiceImpl 底层继承了 IService
                     this.page是调用IService中的page(分页对象,分页查询条件)方法
         */
        Page<Media> pageResult = this.page(page, queryWrapper);
        //查询所有数据
        List<Media> records = pageResult.getRecords();
        //查询数据的总条数
        long total = pageResult.getTotal();
 /*todo 6 获取数据并封装返回
                将查询到的pojo数据转换成PageVo对象响应给前端
                PageVO 对象中封装着前端需要的数据,pojo实体中数据过多*/
        List<MediaDTO> dtos = Collections.EMPTY_LIST;
        //判断查询到的数据是否为空
        if(!(CollectionUtils.isEmpty(records))){
            dtos = MediaConvert.INSTANCE.entitys2dtos(records);
        }
        PageVO pageVO = new PageVO(dtos, total, params.getPageNo(), params.getPageSize());
        return pageVO;
    }
/*
   todo 媒资预览:
        1 判断关键数据
        mediaId companyId
        2 判断mediaId companyId是否存在
        3 判断是否被删除
        4从阿里云获取媒资地址
        5使用redis缓存,缓存没有进入阿里云查询
        5返回结果
 */
    @Override
    public String getVODUrl(Long mediaId, Long companyId) {
        //判断关键数据
        if(ObjectUtils.isEmpty(mediaId)){
            ExceptionCast.cast(CommonErrorCode.E_100101);
        }
        if(ObjectUtils.isEmpty(companyId)){
            ExceptionCast.cast(CommonErrorCode.E_110009);
        }
        //判断想要预览的信息是否存在
        Media media = this.getById(mediaId);
        if(ObjectUtils.isEmpty(media)){
            ExceptionCast.cast(CommonErrorCode.E_100104);
        }
        //判断传入的机构id是否正确,看是否有权限
        if(!(media.getCompanyId().equals(companyId))){
            ExceptionCast.cast(CommonErrorCode.E_100108);
        }
        String playUrl = getPlayUrl(media.getFileId());

        return playUrl;
    }



    private String getPlayUrl(String fileId) {

        String playUrl = "";
        // 需要通过redis来保存url数据,获取时先从redis中查询相关路径,redis中也是可以--value格式
        playUrl = (String) redisTemplate.opsForValue().get(fileId);
        try {
            //获取阿里云客户端对象
            DefaultAcsClient client =
                    AliyunVODUtil.initVodClient(region,accessKeyId,accessKeySecret);
            //获取阿里云响应对象
            GetPlayInfoResponse response = AliyunVODUtil.getPlayInfo(client,fileId,65L);

            List<GetPlayInfoResponse.PlayInfo> playInfoList = response.getPlayInfoList();

            if (!(ObjectUtils.isEmpty(playInfoList))) {
                GetPlayInfoResponse.PlayInfo playInfo = playInfoList.get(0);
                playUrl = playInfo.getPlayURL();
                redisTemplate.opsForValue().set(fileId,playUrl);
            }

            // 需要通过redis来保存url数据（代实现）

        } catch (Exception e) {
            ExceptionCast.cast(MediaErrorCode.E_140014);
        }
        return playUrl;
    }
/*
todo 删除媒资
          业务分析:
           1判断关键数据
           2判断状态
           3逻辑删除
 */
    @Override
    public void removeMedia(Long mediaId,Long companyId) {

//todo 1 判断课程,和教学机构id是否正确
        if (ObjectUtils.isEmpty(mediaId)) {
            throw new RuntimeException("课程id不能为空");
        }
        if (ObjectUtils.isEmpty(companyId)) {
            throw new RuntimeException(CommonErrorCode.E_100101.getDesc());
        }
        //todo 2 判断课程状态,已提交,审核通过,课程已发布,这三种状态无法删除
        Media media = this.getById(mediaId);
        String auditStatus = media.getAuditStatus();
        if (CourseAuditEnum.AUDIT_COMMIT_STATUS.equals(auditStatus) ||
                CourseAuditEnum.AUDIT_PASTED_STATUS.equals(auditStatus) ||
                CourseAuditEnum.AUDIT_PUBLISHED_STATUS.equals(auditStatus)
        ) {
            throw new RuntimeException("课程审核状态异常,无法删除");
        }
        //todo 3逻辑删除,只是让其查询不到,修改其状态就可以
        //todo 注意这里使用的是LambdaUpdateWrapper
        LambdaUpdateWrapper<Media> queryWrapper = new LambdaUpdateWrapper<>();
        queryWrapper.set(Media::getStatus, CommonEnum.DELETE_FLAG.getCodeInt());
        queryWrapper.eq(Media::getId,mediaId);
        boolean update = this.update(queryWrapper);
        if(!update){
            ExceptionCast.cast(MediaErrorCode.E_140002);
        }

    }
/*todo 微服务远程调用   课程计划绑定媒资信息
        业务分析：
            *   PS：由于是学成内部微服务间的调用，此功能只需要提供基础数据即可，不需要加上业务逻辑判断
            *   如果为了数据的完整性，可以对传入和传出的参数进行判断
            *
            *   1.判断mediaid是否为空
            *   2.查询数据
            *   3.判断数据是否存在
            *   4.如果存在，使用RestResponse来封装返回
 */
    @Override
    public RestResponse<MediaDTO> getMediaById4s(Long mediaId) {
        //todo  1.判断mediaid是否为空
        if(ObjectUtils.isEmpty(mediaId)){
            return  RestResponse.validfail(CommonErrorCode.E_100101);
        }
        //todo 2查询媒资信息
        Media media = this.getById(mediaId);
        if(ObjectUtils.isEmpty(media)){
            return   RestResponse.validfail(MediaErrorCode.E_140005);
        }else {
            //todo 媒资存在  po转dto传回前端
            MediaDTO mediaDTO = MediaConvert.INSTANCE.entity2dto(media);
            return RestResponse.success(mediaDTO);
        }
    }

}
